//////////////////////////////////////////////////////////////////////////////////
//	 Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <wx/dcbuffer.h>
#include <wx/pen.h> 
#include "traficgraph.h"

#define NET_MAX_SPEED 			1024*1024*80
#define MAX_STORED_POINTS		2*60*60 /*24*60*60/30*/

#define LEFT_SPACER				80
#define GRAPH_SPACER			20
#define TIME_LABEL_GAP			4
#define TRAFIC_LABEL_GAP		4

#define DEF_TIME_PERIOD			120

#define MIN_BLOCK_SIZE			20
#define MIN_TIME_BLOCK_SIZE		40

static int nTrafBlocks[] = {8,4,2,1};
static int nTimeBlocks[] = {10,5,3,2,1};

CTraficGraph::CTraficGraph(wxWindow* parent, wxWindowID id):
	wxPanel(parent, id,wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL),
	m_timer(this), m_nUpdateTime(1000), m_nTimePeriodSec(DEF_TIME_PERIOD),
	m_strCurIntName(wxT("ppp"))
{
	SetBackgroundStyle(wxBG_STYLE_CUSTOM);
	
	Connect(wxEVT_PAINT, wxPaintEventHandler(CTraficGraph::OnPaint));
	Connect(wxEVT_SIZE, wxSizeEventHandler(CTraficGraph::OnSize));
	Connect(wxEVT_TIMER, wxTimerEventHandler(CTraficGraph::OnTimer));
	
	if ( !m_timer.IsRunning() )
		m_timer.Start(m_nUpdateTime); //One per second

	SetMinSize(wxSize(400,200));

	m_clrRecv = *wxBLUE; 
	m_clrTransm = *wxRED;
}


CTraficGraph::~CTraficGraph()
{
	if ( m_timer.IsRunning() )
		m_timer.Stop();
}

int CTraficGraph::GetGraphLeftWidth()
{
	return LEFT_SPACER;
}

int CTraficGraph::GetGraphWidth()
{
	return 0;
}

int CTraficGraph::GetGraphColWidth()
{
	return 0;
}

void CTraficGraph::SetUpdateInterVal(unsigned int nUpdateTime)
{
	if ( m_timer.IsRunning() )
		m_timer.Stop();
	
	m_nUpdateTime = nUpdateTime;
	
	m_timer.Start(m_nUpdateTime);
}

void CTraficGraph::OnTimer(wxTimerEvent& event)
{
	/*
	time_t tExp = time(NULL);
	tExp-=m_nTimePeriodSec+2*LOW_UPDATE_SPEED;

	TRAFFICDATASTORAGE::iterator iCur;

	for(iCur=m_lstReceive.begin();iCur!=m_lstReceive.end();iCur++)
		RemoveOldValues(iCur->second,   tExp);

	for(iCur=m_lstTransmith.begin();iCur!=m_lstTransmith.end();iCur++)
		RemoveOldValues(iCur->second,   tExp);
	*/


	Refresh();	
}

void CTraficGraph::SetRecvColor(const wxColor& cl)
{
	m_clrRecv = cl;

	Refresh();
}

void CTraficGraph::SetTransmColor(const wxColor& cl)
{
	m_clrTransm = cl;

	Refresh();
}

void CTraficGraph::OnSize(wxSizeEvent& event)
{
	Refresh();
}

void CTraficGraph::OnPaint(wxPaintEvent& event)
{
	try
	{
		wxSize szMe = GetClientSize();
		wxBufferedPaintDC dc(this);

		wxBrush br(GetBackgroundColour());

		//Clear
		dc.SetBackground(br);
		dc.Clear();
		
		unsigned long lTransMax = GetMax( GetInterfaceData(m_lstTransmith) );
		unsigned long lRecvMax 	= GetMax( GetInterfaceData(m_lstReceive)   );

		unsigned long lDataMax  = std::max(lTransMax, lRecvMax);

		//lDataMax must be in kilo bits
		lDataMax*=8;

		wxRect rectGraphArea;
		DrawGrid( dc, lDataMax,  rectGraphArea );

		//dc.SetLogicalFunction(wxAND);

		wxRegion ra, rb;

		if (lTransMax>lRecvMax)
		{
			DrawGraph(dc, GetInterfaceData(m_lstTransmith), rectGraphArea, m_clrTransm, ra);
			DrawGraph(dc, GetInterfaceData(m_lstReceive),   rectGraphArea, m_clrRecv, rb);
		}
		else
		{
			DrawGraph(dc, GetInterfaceData(m_lstReceive),   rectGraphArea, m_clrRecv, ra);
			DrawGraph(dc, GetInterfaceData(m_lstTransmith), rectGraphArea, m_clrTransm, rb);
		}

		//dc.SetLogicalFunction(wxCOPY);

		/*
		if ( ra.Intersect(rb) )
		{
			if ( !ra.GetBox().IsEmpty() )
			{
				wxBrush brsh( *wxBLACK, wxHORIZONTAL_HATCH );
				dc.SetBrush(brsh);
				dc.SetClippingRegion( ra );
				dc.DrawRectangle( ra.GetBox() );
				dc.DestroyClippingRegion();
			}
		}*/

		DrawGridLines(dc, rectGraphArea.x, rectGraphArea.y, rectGraphArea.width, rectGraphArea.height);
	}
	catch(...)
	{
	}
}

void CTraficGraph::CalculateBlockParams( int nLineLength, int* nBlocksMap, int nMapSize,
										 int nBlockMinSize, int &nBlockSize, int& nBlockCount )
{
	nBlockCount = 1;
	nBlockSize  = nLineLength;

	for (int i=0;i<nMapSize;i++)
	{
		if ( nLineLength/nBlocksMap[i]>=nBlockMinSize )
		{
			nBlockCount = nBlocksMap[i];
			nBlockSize  = nLineLength/nBlocksMap[i];
			break;
		}
	}
}

void CTraficGraph::DrawGrid( class wxBufferedPaintDC& dc, unsigned int lDataMax,
		wxRect&  rectGraphArea)
{
	wxSize szMe = GetClientSize();
	int xStart = LEFT_SPACER;
	int yStart = GRAPH_SPACER;
	int w = szMe.GetWidth()-LEFT_SPACER-GRAPH_SPACER;
	int h = szMe.GetHeight()-2*GRAPH_SPACER;

	CalculateBlockParams(h, nTrafBlocks,sizeof(nTrafBlocks)/sizeof(nTrafBlocks[0]),
		MIN_BLOCK_SIZE, m_nTrafBlockSize, m_nTrafBlockCount);

	CalculateBlockParams(w, nTimeBlocks,sizeof(nTimeBlocks)/sizeof(nTimeBlocks[0]),
		MIN_TIME_BLOCK_SIZE, m_nTimeBlockSize, m_nTimeBlockCount);

	//Correct Height
	h=m_nTrafBlockCount*m_nTrafBlockSize;
	yStart = (szMe.GetHeight()-h)/2;

	//Correct Width
	w=m_nTimeBlockCount*m_nTimeBlockSize;

	rectGraphArea.x = xStart;
	rectGraphArea.y = yStart;
	rectGraphArea.width  = w;
	rectGraphArea.height = h;

	//Draw BOX
	wxBrush br(*wxWHITE);
	dc.SetBrush(br);

	dc.DrawRectangle(xStart, yStart, w, h);

	DrawTimeLabels(dc,xStart, yStart, w, h);
	DrawTraphicLabels(dc, xStart, yStart, w, h, lDataMax);
}

//Vertical labels
void CTraficGraph::DrawTraphicLabels( class wxBufferedPaintDC& dc, int x, int y, int w, int h,
									 unsigned int lDataMax )
{
	m_lUpLevel  = CalculateUpLevel( lDataMax );
	unsigned int lPerBlock = m_lUpLevel/m_nTrafBlockCount;


	int wText, hText;
	
	wxFont  font(8, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL|wxFONTFLAG_ANTIALIASED);

	dc.SetFont(font);

	for (int i=0;i<=m_nTrafBlockCount;i++)
	{
		int yTxtCenter = y +h - i*m_nTrafBlockSize;

		wxString strLabel = FormatLabel(i*lPerBlock, lDataMax);

		dc.GetTextExtent(strLabel, &wText, &hText);

		int yTxt = yTxtCenter-hText/2;
		int xTxt = x-wText-TRAFIC_LABEL_GAP;

		dc.DrawText( strLabel, xTxt, yTxt );
	}
}

/*
wxString CTraficGraph::FormatTime(int nTimeBlockIndex)
{
	int nTimePerBlock = m_nTimePeriodSec/m_nTimeBlockCount;

	wxString strLabel = wxString::Format(wxT("%u"),nTimeBlockIndex*nTimePerBlock);

	if (!nTimeBlockIndex) strLabel=_("now");

	if (nTimeBlockIndex==m_nTimeBlockCount)
	{
		strLabel+=wxT(" ");
		strLabel+=_("seconds");
	}

	return strLabel;
}*/

wxString CTraficGraph::FormatTime(int nTimeBlockIndex)
{
	int nTimePerBlock = m_nTimePeriodSec/m_nTimeBlockCount;

	struct Format {
		unsigned long		factor;
		const wxChar*		string;
	};

	const Format f[]=
	{
		{1,		_("seconds") },
		{60,	_("minutes") },
		{60*60, _("hours") } 
	};

	unsigned long		factor=1;
	const wxChar*		strTimeLbl=NULL;

	for(int i=0;i<sizeof(f)/sizeof(f[0]);i++)
	{
		if ( nTimePerBlock/f[i].factor<60 )
		{
			factor = f[i].factor;
			strTimeLbl = f[i].string;
			break;
		}
	}

	wxString strLabel = wxString::Format(wxT("%u"), (nTimeBlockIndex*nTimePerBlock)/factor );

	if (!nTimeBlockIndex) strLabel=_("now");

	if (nTimeBlockIndex==m_nTimeBlockCount)
	{
		strLabel+=wxT(" ");
		strLabel+=strTimeLbl;
	}

	return strLabel;
}


//Horizontal labels
void CTraficGraph::DrawTimeLabels(class wxBufferedPaintDC& dc, int x, int y, int w, int h)
{
	int wText, hText;
	int yLab = y+h+TIME_LABEL_GAP;
	wxFont  font(8, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL|wxFONTFLAG_ANTIALIASED);

	dc.SetFont(font);

	for (int i=0;i<=m_nTimeBlockCount;i++)
	{
		int xTxtCenter = x +w - i*m_nTimeBlockSize;

		wxString strLabel = FormatTime(i);

		dc.GetTextExtent(strLabel, &wText, &hText);

		int xTxt = xTxtCenter-wText/2;

		dc.DrawText( strLabel, xTxt, yLab);
	}
}

void CTraficGraph::DrawGridLines(class wxBufferedPaintDC& dc, int x, int y, int w, int h)
{
	wxPen pen(*wxBLACK,1,wxDOT);
	dc.SetPen(pen);

	//Horizontal blocks
	for (int i=1;i<m_nTrafBlockCount;i++)
	{
		int yBl = y+h - i*m_nTrafBlockSize;

		dc.DrawLine(x,yBl, x+w,yBl);
	}

	//Vert Blocks
	for (int i=1;i<m_nTimeBlockCount;i++)
	{
		int xBl = x+w - i*m_nTimeBlockSize;

		dc.DrawLine(xBl,y, xBl,y+h);
	}
}


//new>old
void CTraficGraph::DrawGraph(class wxBufferedPaintDC& dc, const TRAFFICDATA& data,
							 const wxRect& rect, const wxColor& color, wxRegion& rg)
{
	dc.DestroyClippingRegion();
	dc.SetClippingRegion(rect.Deflate(1,1) );

	wxSize szMe = GetClientSize();

	time_t tStart;

	wxPen   pen(*wxBLACK, 2);
	wxBrush br(color);

	dc.SetPen(pen);
	dc.SetBrush(br);

	time_t tExp = time(NULL);
	tExp-=60+m_nTimePeriodSec;

	if ( data.size()>=3)
	{
		tStart = data.begin()->t;

		TRAFFICDATA::const_iterator iTmp;

		std::vector<wxPoint> list;

		for ( TRAFFICDATA::const_iterator iCur = data.begin();
				iCur!=data.end();iCur++ )
		{
			iTmp=iCur;

			const TRAFFICDATAENTRY& entry1 = *iTmp;
			iTmp++;  if (iTmp==data.end()) break;
			const TRAFFICDATAENTRY& entry2 = *iTmp;
			iTmp++;  if (iTmp==data.end()) break;
			const TRAFFICDATAENTRY& entry3 = *iTmp;

			int x, y, x1, y1;

			if ( !GetDistance( entry1, entry2, x,  y  ) ) continue;
			if ( !GetDistance( entry2, entry3, x1, y1 ) ) continue;

			float fTimeDist  = tStart-x;
			float fTimeDist1 = tStart-x1;

			fTimeDist/=m_nTimePeriodSec;
			fTimeDist1/=m_nTimePeriodSec;

			int xs  =rect.x+rect.width- fTimeDist*rect.width;
			int xs1 =rect.x+rect.width- fTimeDist1*rect.width;

			if (xs<0)
			{
				xs = rect.x;
			}

			if (xs1<0)
			{
				xs1 = rect.x;;
			}

			//scale y
			y*=8;
			y1*=8;

			float fTrafDist  = m_lUpLevel-y;
			float fTrafDist1 = m_lUpLevel-y1;

			fTrafDist/=m_lUpLevel;
			fTrafDist1/=m_lUpLevel;

			y   = rect.y+ fTrafDist*rect.height; 
			y1  = rect.y+ fTrafDist1*rect.height;

			if ( list.empty() )
			{
				//add first two points
				list.push_back( wxPoint(rect.x+rect.width,rect.y+rect.height+2) ); //2 to avoid buggy drawing
				list.push_back( wxPoint(rect.x+rect.width,y) );
			}

			list.push_back( wxPoint(xs,y)   ); 
			list.push_back( wxPoint(xs1,y1) );

			//dc.DrawLine(xs,y,xs1,y1);

			if ( fTimeDist>1.0 || fTimeDist1>1.0 )
				break;

			//Do not count expired values
			if ( entry1.t < tExp  )
				break;
		}

		if ( !list.empty() )
		{
			//Add last point
			wxPoint pt = list.back();

			if ( pt.x<0 )
			{
				pt.x = rect.x;
			}

			pt.y =  rect.y+rect.height+2; //2 to avoid buggy drawing
			list.push_back( pt );

			if ( list.size()>4 )
			{
				std::vector<wxPoint>::iterator iCur;
				wxPoint* points = new wxPoint[list.size()];

				int i=0;
			
				for (iCur=list.begin();iCur!=list.end();iCur++, i++)
				{
					points[i].x = iCur->x;
					points[i].y = iCur->y;
				}
				
				dc.DrawPolygon ( list.size(), points  );

				rg = wxRegion( list.size(), points );
				
				delete[] points;
			}
		}
	}
}


////////////////////////////////////////////////////////////////////////////////////////////
//UTL
bool CTraficGraph::GetDistance(const TRAFFICDATAENTRY& entry1, const TRAFFICDATAENTRY& entry2, int& x, int& y)
{
	bool bRes(false);

	y=0;
	x=0;

	if ( entry1.data >= entry2.data )
	{
		time_t tDelta1 = entry1.t-entry2.t;
		unsigned long lValue1 = entry1.data - entry2.data;
		if ( tDelta1 ) lValue1/=tDelta1;

		y = (int)lValue1;
		x = (int)entry1.t;

		bRes = true;
	}

	return bRes;
}

unsigned int CTraficGraph::CalculateUpLevel( unsigned int lDataMax )
{
	unsigned long lData=GetScale(lDataMax);
	lData=lData<1024?1024:lData;

	while (lDataMax/lData>10) 
	{
		lData*=10;
	} 

	unsigned int lMaxFac = (lDataMax)/lData;
	unsigned int lMax = (lMaxFac+1)*lData;

	return lMax;
}


unsigned long CTraficGraph::GetScale(unsigned long lMax)
{
	unsigned long lScale(1);
	
	if ( lMax <  (1L << 10) )
	{
		lScale =  1L << 10;
	}
	else if ( lMax <  (1L << 20) )
	{
		lScale =  1L << 20;
	}
	else if ( lMax <  (1L << 30) )
	{
		lScale =  1L << 30;
	}
		
	return lScale/1024;
}

wxString CTraficGraph::FormatLabel( unsigned long lVal, unsigned long lMax)
{
	struct Format {
		unsigned long factor;
		const wxChar* string;
	};

	float fRes = (float)lVal;

	const Format all_formats[3] =
	{
		{ 1UL << 10,	_("%.1f KiB/s") },
		{ 1UL << 20,	_("%.1f MiB/s") },
		{ 1UL << 30,	_("%.1f GiB/s") }
	};
	
	wxString strFormat = _("%.1f bits/s");

	if ( lMax>all_formats[0].factor)
	{
		for (size_t i=0;i<sizeof(all_formats)/sizeof(all_formats[0]);i++)
		{
			if ( lMax < all_formats[i].factor )
			{
				strFormat = all_formats[i-1].string;
				fRes/=all_formats[i-1].factor;
				break;
			}
		}
	}
	
	return  wxString::Format(strFormat, fRes);
}


////////////////////////////////////////////////////////////////////////////////////////////
// Data Management
/*
void CTraficGraph::ConvertToBandwidth(TRAFFICDATA& data, BANDWIDTHDATA& bndwdata)
{
	if ( data.size()>=2)
	{
		for ( TRAFFICDATA::iterator iCur = data.begin();
				iCur!=data.end();iCur++ )
		{
			TRAFFICDATAENTRY& entryPrev = *iCur;
			iCur++;
			TRAFFICDATAENTRY& entryNext = *iCur;
			
			time_t tDelta = entryNext.t-entryPrev.t;
			unsigned long lValue = entryNext.data - entryPrev.data;
			
			if ( tDelta ) lValue/=tDelta;

			bndwdata.push_back( lValue );
		}
	}
}
*/

//remove old values
void CTraficGraph::RemoveOldValues(TRAFFICDATA& data, time_t tExpired)
{
	TRAFFICDATA::iterator iCur = data.begin();

	for ( ;iCur!=data.end();iCur++ )
	{
		TRAFFICDATAENTRY& entryPrev = *iCur;

		if ( entryPrev.t < tExpired )
			break;
	}

	if ( iCur != data.end() )
		data.erase(iCur, data.end());
}

//new values stored in front
void CTraficGraph::AddData( const wxString& strIntName,
						    TRAFFICDATASTORAGE& data,
							unsigned long long lVal,
							time_t tEvent )
{
	TRAFFICDATAENTRY entry;
	
	entry.t 	= tEvent;
	entry.data	= lVal;

	TRAFFICDATASTORAGE::iterator iCur=data.find(strIntName);

	if ( iCur==data.end() )
	{
		TRAFFICDATA trData;
		trData.push_front( entry );
		data[strIntName] = trData;
	}
	else
	{
		iCur->second.push_front( entry );

		if ( iCur->second.size()>MAX_STORED_POINTS ) CompressList( iCur->second );
	}
}

unsigned long CTraficGraph::GetMax( const TRAFFICDATA& data )
{
	unsigned long lMax(0);

	time_t tExp = time(NULL);
	tExp-=m_nTimePeriodSec;
	
	if ( data.size()>=2)
	{
		TRAFFICDATA::const_iterator iTmp;

		for ( TRAFFICDATA::const_iterator iCur = data.begin();
				iCur!=data.end();iCur++ )
		{
			iTmp = iCur;
			const TRAFFICDATAENTRY& entryNew = *iTmp;
			iTmp++; if (iTmp==data.end()) break;
			const TRAFFICDATAENTRY& entryOld = *iTmp;

			//Do not count expired values
			if ( entryOld.t < tExp  )
				break;
			
			time_t tDelta = entryNew.t-entryOld.t;
			unsigned long lValue = 0;
			
			if ( entryNew.data > entryOld.data )
				lValue = entryNew.data - entryOld.data;
			
			if ( tDelta ) lValue/=tDelta;

			if ( lValue>lMax) lMax=lValue;
		}
	}
	
	return lMax;
}

void CTraficGraph::SetRecv(  const wxString&  strIntName, unsigned long long lRecv, time_t tEvent  )
{
	AddData( strIntName, m_lstReceive, lRecv, tEvent );
}

void CTraficGraph::SetTransm( const wxString&  strIntName, unsigned long long  lTransm, time_t tEvent )
{
	AddData( strIntName, m_lstTransmith, lTransm, tEvent );
}

////////////////////////////////////////////////////////////////////////////////
wxString format_size(unsigned long long size, unsigned long long max_size, bool want_bits)
{
	enum {
		K_INDEX,
		M_INDEX,
		G_INDEX
	};

	struct Format {
		unsigned long long  factor;
		const wxChar*		string;
	};

	const Format all_formats[2][3] = {
		{ { 1UL << 10,	_("%.1f KiB") },
		  { 1UL << 20,	_("%.1f MiB") },
		  { 1UL << 30,	_("%.1f GiB") } },
		{ { 1000,		_("%.1f kbit") },
		  { 1000000,	_("%.1f Mbit") },
		  { 1000000000,	_("%.1f Gbit") } }
	};

	const Format (&formats)[3] = all_formats[want_bits ? 1 : 0];

	if (want_bits)
	{
		size *= 8;
		max_size *= 8;
	}

	if (max_size == 0)
		max_size = size;

	if (max_size < formats[K_INDEX].factor)
	{
		const wxChar *format=NULL;

		if ( want_bits )
		{
			format = size==1?_("%u bit"):_("%u bits");
		}
		else
		{
			format = size==1?_("%u byte"):_("%u bytes");
		}

		return wxString::Format(format, (unsigned int)size);
	}
	else
	{
		unsigned long long factor;
		const wxChar* format = NULL;

		if (max_size < formats[M_INDEX].factor) {
		  factor = formats[K_INDEX].factor;
		  format = formats[K_INDEX].string;
		} else if (max_size < formats[G_INDEX].factor) {
		  factor = formats[M_INDEX].factor;
		  format = formats[M_INDEX].string;
		} else {
		  factor = formats[G_INDEX].factor;
		  format = formats[G_INDEX].string;
		}

		return wxString::Format(format, size /(double)factor);
	}
}


wxString CTraficGraph::GetRecvTotal()
{
	unsigned long long l=0;

	const TRAFFICDATA&	lstReceive = GetInterfaceData( m_lstReceive );

	if ( !lstReceive.empty() )
	{
		l = lstReceive.begin()->data;
	}

	return format_size(l, l, false);
}

wxString CTraficGraph::GetRecvRate()
{
	unsigned long l = GetCurBandwidth( GetInterfaceData( m_lstReceive ) );
	return format_size(l, l, true)+wxT("/s");
}

wxString CTraficGraph::GetSendTotal()
{
	unsigned long long l=0;

	const TRAFFICDATA&	lstTransmith = GetInterfaceData( m_lstTransmith );

	if ( !lstTransmith.empty() )
	{
		l = lstTransmith.begin()->data;
	}

	return format_size(l, l, false);
}

wxString CTraficGraph::GetSendRate()
{
	unsigned long l = GetCurBandwidth( GetInterfaceData(m_lstTransmith) );
	return format_size(l, l, true)+wxT("/s");
}

unsigned long CTraficGraph::GetCurBandwidth(const TRAFFICDATA& data)
{
	unsigned long lRes(0);

	if ( data.size()>=2 )
	{
		TRAFFICDATA::const_iterator iTmp = data.begin();
		const TRAFFICDATAENTRY& entry1 = *iTmp;
		iTmp++;
		const TRAFFICDATAENTRY& entry2 = *iTmp;

		int x, y;

		GetDistance( entry1, entry2, x,  y  );

		lRes = y;
	}

	return lRes;
}

void CTraficGraph::SetTimePeriod(int nPer)
{
	m_nTimePeriodSec = nPer;
	Refresh();
}

void  CTraficGraph::SetInterface(const wxString& strName)
{
	m_strCurIntName = strName;
	Refresh();
}

const CTraficGraph::TRAFFICDATA& CTraficGraph::GetInterfaceData( const TRAFFICDATASTORAGE& storage )
{
	static TRAFFICDATA emptyData;

	TRAFFICDATASTORAGE::const_iterator iCur = storage.find( m_strCurIntName );

	if ( iCur==storage.end() )
		return emptyData;
	else
		return iCur->second;
}

void CTraficGraph::CompressList( TRAFFICDATA& data )
{
	time_t tNow = time(NULL);

	try
	{
		TRAFFICDATA dataNew;

		wxSize szMe    = GetClientSize();

		TRAFFICDATA::iterator iCur   = data.begin();
		TRAFFICDATA::iterator iStart = data.begin();

		//Keep one hour of actual data
		for ( ;iCur!=iStart;iCur++ )
		{
			if ( tNow-iCur->t>60*60 )
			{
				break;
			}
			dataNew.push_back(*iCur);
		}

		for ( ;iCur!=data.end();iCur++ )
		{
			TRAFFICDATAENTRY a = *iCur;

			//get next point
			iCur++;

			//Last point
			if (iCur==data.end())
			{
				dataNew.push_back(a);
				break;
			}
			else
			{
				const TRAFFICDATAENTRY& b = *iCur;

				if (!a.bCompressed && !b.bCompressed )
				{
					a.data = (a.data+b.data)/2;
					a.t    = (a.t+b.t)/2;
					a.bCompressed = true;
				}
			}

			dataNew.push_back(a);
		}

		data = dataNew;
	}
	catch(...)
	{
	}
}

void  CTraficGraph::Reset()
{
	time_t tNow = time(NULL);

	for (TRAFFICDATASTORAGE::const_iterator iCur = m_lstReceive.begin();
		iCur!=m_lstReceive.end();++iCur)
	{
		SetRecv( iCur->first, 0, tNow );
	}

	for (TRAFFICDATASTORAGE::const_iterator iCur = m_lstTransmith.begin();
		iCur!=m_lstTransmith.end();++iCur)
	{
		SetTransm( iCur->first, 0, tNow );
	}
}
